package top.eggcode.component.session;

import lombok.Data;
import top.eggcode.common.exception.ApplicationException;
import top.eggcode.component.session.exception.ExpiredSessionException;
import top.eggcode.component.session.exception.InvalidSessionException;
import top.eggcode.component.session.exception.StoppedSessionException;

import java.io.Serializable;
import java.util.Collection;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Title: 自定义用户会话
 * Description: TODO
 * Date: 2021/6/9 17:33
 *
 * @author JiaQi Ding
 * @version 1.0
 */
@Data
public class SimpleSession implements Session {

    /**
     * 主键
     */
    private Serializable id;
    /**
     * 会话创建时间
     */
    private Date startTimestamp;
    /**
     * 会话停止时间
     */
    private Date stopTimestamp;
    /**
     * 最后访问时间
     */
    private Date lastAccessTime;
    /**
     * 生存时长，单位：秒
     */
    private long timeout;

    /**
     * 主机地址
     */
    private String host;

    /**
     * 到期标注
     */
    private boolean expired;

    /**
     * 用户属性集合
     */
    private Map<Object, Object> attributes;

    private int accessCount;

    public SimpleSession() {
        this.setStartTimestamp(new Date());
        this.setLastAccessTime(new Date());
    }

    @Override
    public void setAttribute(Object key, Object value) {
        if (attributes == null) {
            attributes = new ConcurrentHashMap<>(10);
        }
        attributes.remove(key);
        attributes.put(key, value);
    }

    @Override
    public void touch() {
        this.lastAccessTime = new Date();
    }

    @Override
    public void stop() {
        if (this.stopTimestamp == null) {
            this.stopTimestamp = new Date();
        }
    }

    @Override
    public Collection<Object> getAttributeKeys() {
        return null;
    }

    @Override
    public Object getAttribute(Object key) {
        if (attributes == null) {
            return null;
        }
        return attributes.get(key);
    }

    @Override
    public Object removeAttribute(Object key) {
        Map<Object, Object> attributes = this.getAttributes();
        return attributes == null ? null : attributes.remove(key);
    }

    protected boolean isStopped() {
        return getStopTimestamp() != null;
    }

    public void validate() throws InvalidSessionException {
        if (isStopped()) {
            throw new StoppedSessionException("会话已显示停止，不需要处理。");
        }
        if (isTimeOut()) {
            expire();

            throw new ExpiredSessionException("会话过期");

        }
    }

    protected void expire() {
        stop();
        this.expired = true;
    }

    protected boolean isTimeOut() {
        if (isExpired()) {
            return true;
        }

        long timeout = getTimeout();

        if (timeout >= 0L) {
            Date lastAccessTime = getLastAccessTime();

            if (lastAccessTime == null) {
                throw new ApplicationException("lastAccessTime 属性不能为空，请检查。");
            }

            long expireTimeMillis = System.currentTimeMillis() - timeout;

            Date expireTime = new Date(expireTimeMillis);

            // 最后访问时间必须小于过期时间
            return lastAccessTime.before(expireTime);

        } else {
            // 永不过期
        }

        return false;

    }


}
